package Model.Visible;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;

import Controller.Game.GamePanelController;
import com.sun.org.apache.bcel.internal.generic.GETSTATIC;

import Model.Player.Player;
import Model.Stances.FleetMaker;
import Utils.ConstantsImplement;
import Utils.Timers.Timer;
import Utils.Timers.TimerListener;
import View.GUI.FleetGUI;

/**
 * This class represents a Fleet of ships. <dd>
 * 		-It distributes the ships by the level. <br>
 * 		-The attack are made by a fleet to a planet and vice-versa. A ship never was attacked
 * </dd>
 * @author magal
 *
 */
public class Fleet extends VisibleElements implements TimerListener, ConstantsImplement{

	private ArrayList<Ship> ships;
	private int attack_;
	private int numShips; 
	private Point position_;
	private Timer timer_;
	private boolean isMoving_;
	private boolean isAttaking_;
	private GamePanelController gamePanelController_;
	private FleetGUI fleetGUI_;
	private Planet planetToAttack;
	private Player owner_;
	private double vx;
	private double vy;

	public Point getPosition_(){
		return position_;
	}

	public FleetGUI getFleetGUI(){
		return fleetGUI_;
	}

	public void setFleetGUI_(FleetGUI fleetGUI_) {
		this.fleetGUI_ = fleetGUI_;
	}

	public void setOwner_(Player owner_) {
		this.owner_ = owner_;
	}

	public Player getOwner_() {
		return owner_;
	}

	public double getVx() {
		return vx;
	}

	/**
	 * Simple Constructor
	 * @param fleetGUI 
	 */
	public Fleet(Player owner, GamePanelController gamePanelController) {
		// TODO Auto-generated constructor stub
		attack_ = 0;
		numShips = 0;
		ships = new ArrayList<Ship>();
		timer_ = new Timer(this, 100);
		timer_.setRun_(false);
		timer_.start();
		gamePanelController_ = gamePanelController;
		//fleetGUI_ = fleetGUI;
		position_ = new Point();
		owner_ = owner;
	}

	/**
	 * Calculate the total attack of the Fleet to minimize the calculation.
	 * This was called every time a ship die or enters in the fleet.
	 */
	public void calculateAttackTotal(){
		if(!ships.isEmpty()){
			attack_ = numShips*ships.get(0).getAttack_();
		}else{
			attack_=0;
		}
	}
	/**
	 * This function distributes the damage by the ships 
	 * starting by the firsts that are low level 
	 * @param damage
	 */
	//ARrrumar
	public void distribAttack(int damage){
//		int i = 0, aux = 0;
//		while (damage > 0) {
//			if(i < numShips){
//				aux = (int )(Math.random() % 100); // A decidir
//				if(damage - aux < 0){
//					ships.get(i).takeDamage(aux - damage);
//					damage = damage - aux;
//				}else{
//					ships.get(i).takeDamage(aux);
//					damage = damage - aux;
//					calculateAttackTotal();
//				}
//				if(ships.get(i).isDead()){
//					removeShip(i);
//				}
//				i++;
//			}else{
//				i = 0;
//			}
//		}
//		calculateAttackTotal();
		
		while( damage > 0 && numShips > 0) {
			damage = ships.get(0).takeDamage(damage);
			if (ships.get(0).getHp_() == 0){
				ships.remove(0);
				numShips--;
			}
		}
	}

	/**
	 * Remove a ship from the Fleet
	 * @param i is the index of the ship in ships vector
	 */
	public void removeShip(int i){
		ships.remove(i);
		numShips--;
		calculateAttackTotal();
	}

	/**
	 * Add a ship in Fleet
	 * @param ship is the ship that will be added
	 */
	public void addShip(Ship ship){
		ships.add(ship);
		numShips++;
		calculateAttackTotal();
	}

	//	/**
	//	 * Verify if the Fleet is full
	//	 * @return boolean
	//	 */
	//	public boolean isFull(){
	//		return ships == numShips;
	//	}

	public boolean isEmpty() {
		return numShips ==0;
	}

	public Ship getShip(Integer i){
		return ships.get(i);	
	}

	public Fleet divideFleet(int number, Planet planet){
		System.out.println(numShips);
		Fleet fleet = new Fleet(owner_, gamePanelController_);
		calculateAttackTotal();
		for (int i = 0; i < number /*|| i < numShips */; i++) {
			fleet.addShip(new Ship(position_, 0));
			removeShip(0);
			System.out.println(i);
		}

		fleet.setPosition_((Point) planet.getPosition_().clone());
		return fleet;
	}

	public void go(){
		calculate();
		//		position_.x = (int)Math.round(position_.x + 
		//				FLEET_SPEED*(planetToAttack.getPosition_().x - position_.x)/Point.distance(position_.x,
		//						position_.y, planetToAttack.getPosition_().x, planetToAttack.getPosition_().y));
		//		position_.y = (int)Math.round(position_.y + 
		//				FLEET_SPEED*(planetToAttack.getPosition_().y - position_.y)/Point.distance(position_.y,
		//						position_.y, planetToAttack.getPosition_().y, planetToAttack.getPosition_().y));
		position_.x = (int) Math.round(position_.x + vx);
		position_.y = (int) Math.round(position_.y + vy);
	}

	public void update(){
		if (isMoving_){
			go();
			//System.out.println("Distancia :" + Point.distance(position_.x, position_.y, planetToAttack.getPosition_().x, planetToAttack.getPosition_().y));
			//System.out.println("Posicao :" + planetToAttack.getPosition_().x + " " + planetToAttack.getPosition_().y);
			if(Point.distance(position_.x, position_.y, planetToAttack.getPosition_().x, planetToAttack.getPosition_().y)< 5){
				isMoving_ = false;
				isAttaking_ = true;
			}
		}else if(isAttaking_){
			//System.out.println("Posicao :" + planetToAttack.getPosition_().x + " " + planetToAttack.getPosition_().y);
			this.attack();
		}
		if(ships.isEmpty()){
			//Possible Problem
			gamePanelController_.getUniverse_().getFleets().remove(this);
		}
	}

	private void attack() {
		// TODO Auto-generated method stub
		if(planetToAttack.getOwner() != this.owner_){
		//System.out.println(planetToAttack.getPopulation_());
			if( planetToAttack.getPopulation_() > 0 ){
				planetToAttack.setPopulation_(planetToAttack.getPopulation_() - attack_);
				if (planetToAttack.getDefences_() != null){
					distribAttack(planetToAttack.getDefences_().getAttack_() );
					if (numShips == 0){
						timer_.setRun_(false);
						setMoving_(false);
						gamePanelController_.removeFleetGUI(this.fleetGUI_);
						gamePanelController_.getUniverse_().getFleets().remove(this);
					}
				}
			}
			else{
				//System.out.println("This Owner: " + owner_);
				//System.out.println("Planet To Attack Owner : " + planetToAttack.getOwner() );
				if(planetToAttack.getOwner() != null){
					planetToAttack.getOwner().removePlanet(planetToAttack);
				}
				planetToAttack.setOwner(owner_);
				//System.out.println("This Owner: " + owner_);
				//System.out.println("Planet To Attack Owner : " + planetToAttack.getOwner() );
				planetToAttack.setFleet_(this);
				planetToAttack.setUnderAttack_(false);
				planetToAttack.setPopulation_(0);
				for(int i1=0; i1<planetToAttack.getNumFleets(); i1++){
					int n = planetToAttack.getFleetsAttacking_().get(i1).getNumShips();
					for(int i2=0; i2<n; i2++){
						planetToAttack.getFleet_().addShip(new Ship(new Point(0, 0),ships.get(0).getLevel()));
					}
					planetToAttack.getFleetsAttacking_().remove(i1);
				}
				owner_.addPlanet(planetToAttack);
				gamePanelController_.removeFleetGUI(fleetGUI_);
				gamePanelController_.getUniverse_().getFleets().remove(this);
				timer_.setRun_(false);
				//gamePanelController_.updateFleet();
			}
		}else {
					planetToAttack.setUnderAttack_(false);
					for(int i=0; i<numShips; i++){
						planetToAttack.getFleet_().addShip(new Ship(new Point(0, 0),ships.get(0).getLevel()));
					}
					gamePanelController_.removeFleetGUI(fleetGUI_);
					gamePanelController_.getUniverse_().getFleets().remove(this);
					timer_.setRun_(false);
					//gamePanelController_.updateFleet();
					
			}
	}

	public void updateShips(){
		for (int i = 0; i < numShips; i++) {
			ships.get(i).updateLvl();
		}
	}

	public int getNumShips() {
		return numShips;
	}

	public void setNumShips(int numShips) {
		this.numShips = numShips;
	}

	public boolean isMoving_() {
		return isMoving_;
	}

	public void setMoving_(boolean isMoving_) {
		this.isMoving_ = isMoving_;
		if(isMoving_ == true){
			calculate();
			timer_.setRun_(true);
		}
	}

	private void calculate() {
		// TODO Auto-generated method stub
		double alfa = Math.atan2(planetToAttack.getPosition_().y -position_.y,
				planetToAttack.getPosition_().x -position_.x);
		vx = Math.cos(alfa)*FLEET_SPEED;
		vy = Math.sin(alfa)*FLEET_SPEED;
	}

	public boolean isAttaking_() {
		return isAttaking_;
	}

	public void setAttaking_(boolean isAttaking_) {
		this.isAttaking_ = isAttaking_;
	}

	public Planet getPlanetToAttack() {
		return planetToAttack;
	}

	public void setPlanetToAttack(Planet planetToAttack) {
		this.planetToAttack = planetToAttack;
	}

	public void setPosition_(Point position_) {
		this.position_ = position_;
	}


}
